import {
  Controller,
  UseGuards,
  UploadedFiles,
  BadRequestException,
  Post,
  Get,
  Param,
  Req,
  Delete,
} from '@nestjs/common';
import {
  Crud,
  CrudController,
  Override,
  ParsedRequest,
  ParsedBody,
  CrudRequest,
} from '@nestjsx/crud';
import { ApiTags, ApiBearerAuth, ApiConsumes } from '@nestjs/swagger';
import { deserializeArray } from 'class-transformer';
import { Artist, Album, Song, ArtistEdition } from '../entities';
import { ArtistsService } from '../services';
import { UserRole, FileStoragePath } from '@/enum';
import { Roles } from '@/decorators/roles.decorator';
import { AuthGuard, RolesGuard } from '@/guards';
import { FileUtils } from '@/utils';
import { RequestDtoRelationTransformer } from '@/interfaces';
import { User } from '@/modules/users/entities/user.entity';

@Crud({
  model: {
    type: Artist,
  },
  query: {
    limit: 25,
    maxLimit: 100,
    join: {
      hasSongs: {},
      hasAlbums: {},
      'hasAlbums.hasSongs': {
        alias: 'songsOfAlbum',
      },
      hasProducedAlbums: {},
      editions: {},
      followers: {},
    },
  },
  routes: {
    updateOneBase: {
      // decorators: [
      //   UseGuards(AuthGuard, RolesGuard),
      //   Roles(UserRole.ADMIN),
      //   ApiBearerAuth(),
      // ],
      interceptors: [
        FileUtils.multipleFileUploader(
          '_images',
          ['image'],
          FileStoragePath.LIBRARY_IMAGES,
        ),
      ],
    },
    replaceOneBase: {
      // decorators: [
      //   UseGuards(AuthGuard, RolesGuard),
      //   Roles(UserRole.ADMIN),
      //   ApiBearerAuth(),
      // ],
      interceptors: [
        FileUtils.multipleFileUploader(
          '_images',
          ['image'],
          FileStoragePath.LIBRARY_IMAGES,
        ),
      ],
    },
    deleteOneBase: {
      decorators: [
        UseGuards(AuthGuard, RolesGuard),
        Roles(UserRole.ADMIN),
        ApiBearerAuth(),
      ],
    },
    createOneBase: {
      // decorators: [
      //   UseGuards(AuthGuard, RolesGuard),
      //   Roles(UserRole.ADMIN),
      //   ApiBearerAuth(),
      // ],
      interceptors: [
        FileUtils.multipleFileUploader(
          '_images',
          ['image'],
          FileStoragePath.LIBRARY_IMAGES,
        ),
      ],
    },
    createManyBase: {
      decorators: [
        UseGuards(AuthGuard, RolesGuard),
        Roles(UserRole.ADMIN),
        ApiBearerAuth(),
      ],
    },
  },
})
@ApiTags('artists')
@Controller('resources/artists')
// eslint-disable-next-line prettier/prettier
export class ArtistsController implements CrudController<Artist>, RequestDtoRelationTransformer<Artist> {
  constructor(public service: ArtistsService) {}

  get base(): CrudController<Artist> {
    return this;
  }

  dtoRelationTransform(dto: Artist): Artist {
    try {
      if (typeof dto.images === 'string') {
        dto.images = JSON.parse(dto.images);
      }
      if (typeof dto.hasSongs === 'string') {
        dto.hasSongs = deserializeArray(Song, dto.hasSongs);
      }
      if (typeof dto.hasAlbums === 'string') {
        dto.hasAlbums = deserializeArray(Album, dto.hasAlbums);
      }
      if (typeof dto.hasProducedAlbums === 'string') {
        dto.hasProducedAlbums = deserializeArray(Album, dto.hasProducedAlbums);
      }
      if (typeof dto.editions === 'string') {
        dto.editions = deserializeArray(ArtistEdition, dto.editions);
      }
      if (typeof dto.followers === 'string') {
        dto.followers = deserializeArray(User, dto.followers);
      }
    } catch (e) {
      if (e instanceof SyntaxError) {
        throw new BadRequestException(e.message, e.name);
      }
      throw new BadRequestException();
    }

    return dto;
  }

  /**
   * 查询用户是否关注接口
   * @param id artist id
   * @param req request
   */
  @UseGuards(AuthGuard)
  @Get(':id/follow')
  checkFollowing(@Param() id: number, @Req() req) {
    return this.service.checkFollow(id, req.user.id);
  }

  /**
   * 用户加关注接口
   * @param id artist id
   * @param req request
   */
  @UseGuards(AuthGuard)
  @Post(':id/follow')
  follow(@Param() id: number, @Req() req) {
    return this.service.addFollower(id, req.user.id);
  }

  /**
   * 用户取消关注接口
   * @param id artist id
   * @param req request
   */
  @UseGuards(AuthGuard)
  @Delete(':id/follow')
  unfollow(@Param() id: number, @Req() req) {
    return this.service.removeFollower(id, req.user.id);
  }

  @UseGuards(AuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @Override()
  createOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: Artist,
    @UploadedFiles() _images?: Express.Multer.File[],
  ) {
    dto = this.dtoRelationTransform(dto);
    if (_images && _images.length > 0) {
      if (!dto.images) {
        dto.images = [];
      }
      _images.forEach(i => {
        dto.images.push(i.path);
      });
    }
    return this.base.createOneBase(req, dto);
  }

  @UseGuards(AuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @Override()
  updateOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: Artist,
    @UploadedFiles() _images?: Express.Multer.File[],
  ) {
    dto = this.dtoRelationTransform(dto);
    if (_images && _images.length > 0) {
      if (!dto.images) {
        dto.images = [];
      }
      _images.forEach(i => {
        dto.images.push(i.path);
      });
    }
    return this.base.updateOneBase(req, dto);
  }

  @UseGuards(AuthGuard, RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @Override()
  replaceOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: Artist,
    @UploadedFiles() _images?: Express.Multer.File[],
  ) {
    dto = this.dtoRelationTransform(dto);
    if (_images && _images.length > 0) {
      dto.images = [];
      _images.forEach(i => {
        dto.images.push(i.path);
      });
    }
    return this.base.replaceOneBase(req, dto);
  }
}
